export = {};
/** Conditional Types 条件类型
 TypeScript 2.8 introduces conditional types which add the ability to express non-uniform type mappings. A conditional type selects one of two possible types based on a condition expressed as a type relationship test:
 ts2.8引入了条件类型,增加了表示非均匀类型映射的能力

 T extends U ? X : Y
 The type above means when T is assignable to U the type is X, otherwise the type is Y.
 当T能被赋值给U类型时,得到的类型就为X类型否则为Y类型

 A conditional type T extends U ? X : Y is either resolved to X or Y, or deferred because the condition depends on one or more type variables.
 条件类型 `T extends U ? X : Y` 最终得到的结果不是X就是Y，或则是一个`deferred`(延迟的结果,因为这个结果还取决于一个或更多类型变量)
*/




/** 1. immediately resolved conditional types
 When T or U contains type variables, whether to resolve to X or Y, or to defer, is determined by whether or not the type system has enough information to conclude that T is always assignable to U.
 当T或U包含类型变量时，是否resolve为X或Y，或是deferred，取决于类型系统是否有足够的信息来确定T总是可以分配给U

 As an example of some types that are immediately resolved, we can take a look at the following example:
 作为一些被立即resolved的类型的例子，我们可以看一下以下示例：
*/

/** 1.1 case0*/
declare function f<T extends boolean>(x: T): T extends true ? string : number;

// Type is 'string | number'
let x = f(Math.random() < 0.5)


/** 1.2 case1*/
//Another example would be the TypeName type alias, which uses nested conditional types:
type TypeName<T> =
  T extends string ? "string" :
    T extends number ? "number" :
      T extends boolean ? "boolean" :
        T extends undefined ? "undefined" :
          T extends Function ? "function" :
            "object";

type T0 = TypeName<string>;  // "string"
type T1 = TypeName<"a">;  // "string"
type T2 = TypeName<true>;  // "boolean"
type T3 = TypeName<() => void>;  // "function"
type T4 = TypeName<string[]>;  // "object"


/** 2. deferred conditional types*/
// 但是，作为一个条件类型被推迟的地方的例子——它们在那里逗留而不是选择一个分支——将出现在下面
//But as an example of a place where conditional types are deferred - where they stick around instead of picking a branch - would be in the following:
/** 2.1 case0*/
interface Foo {
  propA: boolean;
  propB: boolean;
}

declare function f<T>(x: T): T extends Foo ? string : number;

function foo<U>(x: U) {
  // Has type 'U extends Foo ? string : number'
  let a = f(x); // 因为在函数体内部U是不确定的,故x类型不确定,a类型也不确定

  // This assignment is allowed though!
  // 但如下赋值是被允许的
  let b: string | number = a; // √
}
/*↑
	在上面，变量a有一个条件类型，尚未选择分支。当另一段代码最终调用foo时，它将用其他类型代替U，TypeScript将重新评估条件类型，决定它是否实际上可以选择分支。
	In the above, the variable a has a conditional type that hasn’t yet chosen a branch. When another piece of code ends up calling foo, it will substitute in U with some other type, and TypeScript will re-evaluate the conditional type, deciding whether it can actually pick a branch.

  同时，只要条件的每个分支都可以分配给该目标，我们就可以将条件类型分配给任何其他目标类型。因此，在我们上面的例子中，我们能够将 `U extends Foo ? string : number` 分配给 `string|number`，因为无论条件计算到什么，它都是字符串或数字。
  In the meantime, we can assign a conditional type to any other target type as long as each branch of the conditional is assignable to that target. So in our example above we were able to assign U extends Foo ? string : number to string | number since no matter what the conditional evaluates to, it’s known to be either string or number.
	*/


/** 和联合类型以及交叉类型一样,条件类型也不能递归引用自己*/
//Similar to union and intersection types, conditional types are not permitted to reference themselves recursively. For example the following is an error.
type ElementType<T> = T extends any[] ? ElementType<T[number]> : T;  // Error
